/** FASSIT (Forms of Selective Attention in Intelligent Transportation Systems)
 * Computational Creativity and Digital Media
 * Cognitive and Media Systems Group
 * Centre for Informatics and Systems of the University of Coimbra (CISUC)
 *
 * Copyright (c) 2010-2013 University of Coimbra, Portugal
 * All rights reserved.
 */
package agent.Metrics.Surprise;

import poi.Surprise.SurpriseDaysOff;
import poi.Surprise.SurprisePrice;
import poi.Surprise.SurpriseSchedule;

/**
 * This class is used to evaluate the metric of Surprise
 * 
 * @author Hernani Costa
 * @version 0.1 date: 3/12/2012
 */
public class SurpriseEvaluator {

	private static SurpriseEvaluator instance;

	/**
	 * ------------------------------------------------------------------------
	 * Constructor class
	 * ------------------------------------------------------------------------
	 */
	public synchronized static SurpriseEvaluator getInstance() {
		if (instance == null)
			instance = new SurpriseEvaluator();
		return instance;
	}

	/**
	 * ------------------------------------------------------------------------
	 * Evaluates the Surprise value for the parameter DaysOff
	 * ------------------------------------------------------------------------
	 * 
	 * @param agent
	 *            - Agent's knowledge for the parameter DaysOff
	 * @param master
	 *            - Real Knowledge for the parameter DaysOff
	 * @return - surprise value for the parameter DaysOff
	 */
	public synchronized double evaluatingDaysOff(SurpriseDaysOff agent,
			SurpriseDaysOff master) {
		double monday = 0.0, tuesday = 0.0, wednesday = 0.0, thusday = 0.0, friday = 0.0, saturday = 0.0, sunday = 0.0;
		double result = 0.0, max = 0.0;

		double[] values = { agent.getMonday(), agent.getTuesday(),
				agent.getWednesday(), agent.getThursday(), agent.getFriday(),
				agent.getSaturday(), agent.getSunday() };
		max = max(values);

		monday = surpriseFormula(max, agent.getMonday(), master.getMonday());
		// System.out.println("Result= " + monday + " max: " + max + " agent: "
		// + agent.getMonday() + " master: " + master.getMonday());

		tuesday = surpriseFormula(max, agent.getTuesday(), master.getTuesday());
		// System.out.println("Result= " + tuesday + " max: " + max + " agent: "
		// + agent.getTuesday() + " master: " + master.getTuesday());

		wednesday = surpriseFormula(max, agent.getWednesday(),
				master.getWednesday());
		// System.out.println("Result= " + wednesday + " max: " + max +
		// " agent: "
		// + agent.getWednesday() + " master: " + master.getWednesday());

		thusday = surpriseFormula(max, agent.getThursday(), master.getThursday());
		// System.out.println("Result= " + thusday + " max: " + max + " agent: "
		// + agent.getThusday() + " master: " + master.getThusday());

		friday = surpriseFormula(max, agent.getFriday(), master.getFriday());
		// System.out.println("Result= " + friday + " max: " + max + " agent: "
		// + agent.getFriday() + " master: " + master.getFriday());

		saturday = surpriseFormula(max, agent.getSaturday(),
				master.getSaturday());
		// System.out.println("Result= " + saturday + " max: " + max +
		// " agent: "
		// + agent.getSaturday() + " master: " + master.getSaturday());

		sunday = surpriseFormula(max, agent.getSunday(), master.getSunday());
		// System.out.println("Result= " + sunday + " max: " + max + " agent: "
		// + agent.getSunday() + " master: " + master.getSunday());

		result = monday + tuesday + wednesday + thusday + friday + saturday
				+ sunday;
		// System.out.println("Final Result= " + result);
		return result;

	}

	/**
	 * ------------------------------------------------------------------------
	 * Evaluates the Surprise value for the parameter Price
	 * ------------------------------------------------------------------------
	 * 
	 * @param agent
	 *            - Agent's knowledge for the parameter Price
	 * @param master
	 *            - Real Knowledge for the parameter Price
	 * @return - surprise value for the parameter Price
	 */
	public synchronized double evaluatingPrice(SurprisePrice agent,
			SurprisePrice master) {
		double cheap = 0.0, average = 0.0, expensive = 0.0;
		double result = 0.0, max = 0.0;

		double[] values = { agent.getCheap(), agent.getAverage(),
				agent.getExpensive() };
		max = max(values);

		cheap = surpriseFormula(max, agent.getCheap(), master.getCheap());
		average = surpriseFormula(max, agent.getAverage(), master.getAverage());
		expensive = surpriseFormula(max, agent.getExpensive(),
				master.getExpensive());

		result = cheap + average + expensive;
		return result;

	}

	/**
	 * ------------------------------------------------------------------------
	 * Evaluates the Surprise value for the parameter Schedule
	 * ------------------------------------------------------------------------
	 * 
	 * @param agent
	 *            - Agent's knowledge for the parameter Schedule
	 * @param master
	 *            - Real Knowledge for the parameter Schedule
	 * @return - surprise value for the parameter Schedule
	 */
	public synchronized double evaluatingSchedule(SurpriseSchedule agent,
			SurpriseSchedule master) {
		double morning = 0.0, afternoon = 0.0, night = 0.0;
		double result = 0.0, max = 0.0;

		double[] values = { agent.getMorning(), agent.getAfternoon(),
				agent.getNight() };
		max = max(values);

		morning = surpriseFormula(max, agent.getMorning(), master.getMorning());
		afternoon = surpriseFormula(max, agent.getAfternoon(),
				master.getAfternoon());
		night = surpriseFormula(max, agent.getNight(), master.getNight());

		result = morning + afternoon + night;
		return result;

	}

	/**
	 * ------------------------------------------------------------------------
	 * Surprise Formula
	 * ------------------------------------------------------------------------
	 * 
	 * @param max
	 *            - max value
	 * @param agent
	 *            - agent value
	 * @param master
	 *            - master agent value
	 * @return
	 */
	private double surpriseFormula(double max, double agent, double master) {
		double result = 0.0;
		result = Math.log(1.0 + max - agent);
		result *= master;
		return result;
	}

	/**
	 * ------------------------------------------------------------------------
	 * Calculates the maximum value from an array of doubles
	 * ------------------------------------------------------------------------
	 * 
	 * @param values
	 *            - values
	 * @return the maximum value
	 */
	private double max(double[] values) {
		double max = 0.0;
		for (int i = 0; i < values.length; i++)
			if (max < values[i])
				max = values[i];

		return max;
	}
}
